const FakeHeaders = {
	'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
	'Accept-Charset': 'UTF-8,*;q=0.5',
	'Accept-Encoding': 'gzip,deflate,sdch',
	'Accept-Language': 'en-US,en;q=0.8',
	'User-Agent':
		'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1',
};

const handleError = (error: any): string => {
	return error.message;
};

// 小红书

const TITLE_REGEX = /<title>(.*?)<\/title>/;
const DESCRIPTION_REGEX = /<meta name="description" content="(.*?)">/;
const BACKUP_URLS_REGEX = /"backupUrls":(\[.+?\])/;
const LINK_REGEX = /(https?:\/\/[^\s|，|,| ]+)/g;

export const extractVideo = async (input: string) => {
	const urls = input.match(LINK_REGEX);
	const url = urls ? urls[0] : input;
	if (url.includes('xhslink.com')) {
		return await xhs(url);
	}
	if (url.includes('instagram.com')) {
		return await instagram(url);
	}
	return '';
};

export const xhs = async (url: string): Promise<string> => {
	try {
		const html = await fetch(url, {
			headers: FakeHeaders,
		}).then(res => res.text());

		console.log(html);
		// Extract title
		const titleMatch = html.match(TITLE_REGEX);
		if (!titleMatch || titleMatch.length !== 2) {
			return 'Failed to parse body';
		}
		const title = titleMatch[1];

		const descMatch = html.match(DESCRIPTION_REGEX);
		const description = descMatch ? descMatch[1] : '';

		// Extract video URLs
		const urlsJSONMatch = html.match(BACKUP_URLS_REGEX);
		if (!urlsJSONMatch || urlsJSONMatch.length !== 2) {
			return 'Failed to parse body';
		}
		const urls: string[] = JSON.parse(urlsJSONMatch[1]);
		return `${title}\n${description}\n链接: ${urls[0]}`;
	} catch (error) {
		return handleError(error);
	}
};

// Instagram

interface SliderItemNode {
	display_url: string; // URL of the Media (resolution is dynamic)
	is_video: boolean; // Is type of the Media equals to video
	video_url: string; // Direct URL to the Video
}

function extractMediaURL(node: SliderItemNode): string {
	return node.is_video ? node.video_url : node.display_url;
}

interface InstagramPayload {
	shortcode_media: {
		id: string; // Unique ID of the Media
		edge_sidecar_to_children: {
			edges: {
				node: SliderItemNode;
			}[];
		};
	};
}

export const instagram = async (url: string) => {
	const parsedUrl = new URL(url);
	const shortCode = extractShortCodeFromLink(parsedUrl.toString());
	if (!shortCode) {
		return "Couldn't extract the media short code from the link";
	}
	return await getPostWithCode(shortCode);
};

function isEmpty(payload: InstagramPayload): boolean {
	return payload.shortcode_media.id === '';
}

async function getPostWithCode(code: string): Promise<string> {
	const URL = `https://www.instagram.com/p/${code}/embed/captioned/`;

	// let embeddedMediaImage = '';
	let embedResponse: InstagramPayload = {
		shortcode_media: {
			id: '',
			edge_sidecar_to_children: {
				edges: [],
			},
		},
	};

	try {
		const html = await fetch(URL, {
			headers: FakeHeaders, // 可能需要随机 ua
		}).then(res => res.text());

		console.log(html);

		const titleMatch = html.match(TITLE_REGEX);
		if (!titleMatch || titleMatch.length !== 2) {
			return 'Failed to parse body';
		}
		const title = titleMatch[1];

		// const embeddedMediaImageMatch = html.match(
		// 	/<img[^>]+class="EmbeddedMediaImage"[^>]+src="([^"]+)"/
		// );
		// embeddedMediaImage = embeddedMediaImageMatch ? embeddedMediaImageMatch[1] : '';

		const gqlDataMatch = html.match(/\\"gql_data\\":([\s\S]*)\}\"\}\]\]\,\[\"NavigationMetrics/);
		if (gqlDataMatch && gqlDataMatch[1]) {
			const jsonString = gqlDataMatch[1].replace(/\\"/g, '"').replace(/\\\\/g, '\\');
			embedResponse = JSON.parse(jsonString);
		}

		if (!isEmpty(embedResponse)) {
			const urls = embedResponse.shortcode_media.edge_sidecar_to_children.edges.map(edge =>
				extractMediaURL(edge.node)
			);
			return `${title}\n${urls.join('/n')}`;
		}

		// if (embeddedMediaImage) {
		// 	return `${title}\n${embeddedMediaImage}`;
		// }

		return 'Failed to fetch the post, the page might be "private", or the link is completely wrong';
	} catch (error) {
		return `Failed to send HTTP request to the Instagram: ${handleError(error)}`;
	}
}

function extractShortCodeFromLink(link: string): string | null {
	const match = link.match(/(p|tv|reel|reels\/videos)\/([A-Za-z0-9-_]+)/);
	return match ? match[2] : null;
}
